package com.bangcommunity.bbframe.springredis.id;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.bangcommunity.bbframe.springredis.RedisClient;

/**
 * Created by tanghc on 17/1/23.
 */
public class RedisId {
    static final Logger logger = LoggerFactory.getLogger(RedisId.class);
    private final static String STATUS_RETURN = "OK";

    private RedisId() {
    }

    private static class RedisIdHolder {
        private static RedisId instance = new RedisId();
    }

    public static RedisId getInstance() {
        return RedisIdHolder.instance;
    }

    /**
     * 获取递增的数值。首次访问时缓存中无数据返回delta。获取失败后等待1ms继续获取,最多等待maxWaitMs。最多尝试次数maxTry
     * 
     * @param key
     *            缓存key值
     * @param delta
     *            递增的步长
     * @param maxWaitMs
     *            最多等待的时长
     * @param maxTry
     *            尝试次数最大值
     */
    public long nextNum(final String key, final long delta, final long maxWaitMs, final int maxTry) {
        logger.debug("start get nextnum: key={}, delta={},maxWaitMs={},maxTry={}", key, delta, maxWaitMs, maxTry);
        Long id = null;
        int trys = 0;
        long expireAt = System.currentTimeMillis() + maxWaitMs;
        while (id == null) {
            if (maxWaitMs > 0 && System.currentTimeMillis() > expireAt) {
                break;
            }
            try {
                id = RedisClient.incr(key, delta);
                if (null != id) {
                    return id.longValue();
                }
            } catch (Exception e) {
                logger.error("get nextnum exception: key={}, delta={},maxWaitMs={},maxTry={}", key, delta, maxWaitMs,
                        maxTry, e);
            }
            if (maxTry > 0 && trys++ > maxTry) {
                break;
            }
            try {
                Thread.sleep(1);
            } catch (InterruptedException e) {
            }
        }
        logger.error("get nextnum fail: key={}, delta={},maxWaitMs={},maxTry={}", key, delta, maxWaitMs, maxTry);
        throw new RuntimeException("get next num fail");
    }

    /**
     * 递增id生成 最多等待3秒
     * 
     * @param key
     * @return
     */
    public long nextId(final String key) {
        return nextNum(key, 1, 3 * 1000, -1);
    }

}
